
#include <GL/gl.h>
#include <math.h>
#include <stdio.h>

#include "o_objet.h"
#include "u_table.h"
#include "t_geometrie.h"

#define max_tab 20
// inclusion du prototype de la fonction de calcul de points sur une courbe
// de Nurbs

/* déclaration de la structure nanoedit */

struct courbe_nurbs
{
  Table_quadruplet Pts_Controle ;
  Table_quadruplet Courbe ;
  Table_flottant vect_nod;
  int degre;
  int nb_points ;
  Booleen pts_controle_affichage;
} ;

int nb_morceaux(int k, int nb_pt_controle) /// Donne le nombre de morceaux du vecteur nodal. Ok!
{
//    int result=0,
//        i;
//    for(i=0;(i+k-1)<nb_pt_controle;i++)
//    {
//        result++;
//    }
//    return result;
    return (nb_pt_controle-k+1);
}

void remplir_vect_nod(struct courbe_nurbs *o) /// Remplis le vecteur nodal qui est en entrée. Ok!
{
    int i,k=o->degre+1,
        morceaux=o->Pts_Controle.nb-k+1;//nb_morceaux(k,nb_pt_controle);

    for(i=0;i<k;i++)
    {
        o->vect_nod.table[i]=0;
    }
    for(i=k;i<k+morceaux;i++)
    {
        o->vect_nod.table[i]=(i-k+1.f)/morceaux;
    }
    for(i=morceaux+k;i<morceaux+2*k-1;i++)
    {
        o->vect_nod.table[i]=1;
    }
}

Quadruplet calcul_point_courbe(struct courbe_nurbs *o,double pas) // pas de cas ou u =0 et u=1 traiter dans une autre fonction.
{
    int degre=o->degre,
        indice=0,
        indice_pt_control=0, //indique le point de control de depart.
        j,i=degre,r,
        k=o->degre+1;

    Quadruplet resultat;
    Table_quadruplet points_temp;
    ALLOUER(points_temp.table,o->Pts_Controle.nb);

    double a;

    while(o->vect_nod.table[i]!=1) // on sait ou se situe "pas" dans le vecteur nodal.
    {
        if(o->vect_nod.table[i]<pas && o->vect_nod.table[i+1]>pas)
        {
            indice_pt_control = indice;
        }
        indice++;
        i++;
    }

    r=k-1+indice_pt_control;

    for(j=0;j < o->Pts_Controle.nb;j++)
    {
        points_temp.table[j] = o->Pts_Controle.table[j];
        points_temp.table[j].x*=points_temp.table[j].h;
        points_temp.table[j].y*=points_temp.table[j].h;
        points_temp.table[j].z*=points_temp.table[j].h;
    }

    for(j=1;j<=degre;j++) //boucle pour le degre
    {
        indice++;
        for(i=r;i>=(r-k+1+j);i--)
        {
            a = ((pas- o->vect_nod.table[i])/(o->vect_nod.table[i+k-j]-o->vect_nod.table[i]));

            points_temp.table[i].x = a * points_temp.table[i].x + (1-a) * points_temp.table[i-1].x;

            points_temp.table[i].y = a * points_temp.table[i].y + (1-a) * points_temp.table[i-1].y;

            points_temp.table[i].z = a * points_temp.table[i].z + (1-a) * points_temp.table[i-1].z;

            points_temp.table[i].h = a * points_temp.table[i].h + (1-a) * points_temp.table[i-1].h;

        }
    }
    i++;
    points_temp.table[i].x/=points_temp.table[i].h;
    points_temp.table[i].y/=points_temp.table[i].h;
    points_temp.table[i].z/=points_temp.table[i].h;

    resultat = points_temp.table[i];
    free(points_temp.table);

    return resultat;
}

Table_quadruplet calcul_courbe_nurbs(struct courbe_nurbs *o)
{
    double i;
    double pas =0.0;
    int indice = 1;

    pas = 1.0/o->nb_points;
    o->Courbe.table[0]=o->Pts_Controle.table[0];

    for(i = pas; i < 1 ;i = i+pas,indice++)
        o->Courbe.table[indice] = calcul_point_courbe(o,i);

    o->Courbe.table[indice] = o->Pts_Controle.table[o->Pts_Controle.nb-1];
    return o->Courbe;
}



static void changement(struct courbe_nurbs *o)
{

    if ( ! (UN_CHAMP_CHANGE(o)||CREATION(o)) )
        return;

    if (CHAMP_CHANGE(o, nb_points) ||  CHAMP_CHANGE(o, Pts_Controle) || CHAMP_CHANGE(o, degre))
    {
        if (o->nb_points > 0 || o->Courbe.nb >= 2)
        {
            free(o->Courbe.table);
            free(o->vect_nod.table);
        }

        if(o->degre > o->Pts_Controle.nb-1)
            o->degre=o->Pts_Controle.nb-1;
        else if(o->degre<1)
            o->degre=1;

        if(o->nb_points<50)
            o->nb_points=50;

        ALLOUER(o->Courbe.table,o->nb_points+1);
        o->Courbe.nb = o->nb_points;


        ALLOUER(o->vect_nod.table,o->degre+o->Pts_Controle.nb+1);
        o->vect_nod.nb=o->degre+o->Pts_Controle.nb+1;

        remplir_vect_nod(o);

        o->Courbe = calcul_courbe_nurbs(o);

        printf("dans changement \n");
    }
    else if(CHAMP_CHANGE(o, vect_nod))
    {
        if (o->nb_points > 0 || o->Courbe.nb >= 2)
            free(o->Courbe.table);

        ALLOUER(o->Courbe.table,o->nb_points+1);
        o->Courbe.nb = o->nb_points;

        o->Courbe = calcul_courbe_nurbs(o);
    }
}


static void affiche_courbe_nurbs(struct courbe_nurbs *o)
{
    int j;

    glBegin(GL_POINTS);
    glColor3d(1,0,0);
    for(j=0 ; j< o->Courbe.nb; j++)
        glVertex3f(o->Courbe.table[j].x,o->Courbe.table[j].y,o->Courbe.table[j].z);
    glEnd();


    if(o->pts_controle_affichage)
    {
        glBegin(GL_LINE);
        glColor3d(0,1,0);
        for(j=0; j < o->Pts_Controle.nb-1; j++)
        {
            glVertex3f(o->Pts_Controle.table[j].x,o->Pts_Controle.table[j].y,o->Pts_Controle.table[j].z);
            glVertex3f(o->Pts_Controle.table[j+1].x,o->Pts_Controle.table[j+1].y,o->Pts_Controle.table[j+1].z);
        }
        glEnd();
    }
}



CLASSE(courbe_nurbs, struct courbe_nurbs,

    CHAMP(Pts_Controle, L_table_point P_table_quadruplet
             Extrait Obligatoire Edite Affiche Sauve)

    CHAMP(Courbe, L_table_point P_table_quadruplet
            Affiche Sauve)

    CHAMP(nb_points, LABEL("Nombre de points")
             L_entier Extrait Affiche Edite Sauve DEFAUT("500"))

    CHAMP(degre, LABEL("Degre de la courbe")
            L_entier Extrait Affiche Edite Sauve DEFAUT("3"))

    CHAMP(pts_controle_affichage, LABEL("Afficher/Désafficher la courbe point de controle?")
            L_booleen Extrait Affiche Edite Sauve DEFAUT("1"))

    CHAMP(vect_nod, L_table_flottant P_table_flottant
          Edite Extrait Affiche Sauve)

    CHANGEMENT(changement)
    CHAMP_VIRTUEL(L_affiche_gl(affiche_courbe_nurbs))


    MENU("Courbe Nurbs")
    EVENEMENT("CN")
)



//
//#include <GL/gl.h>
//#include <math.h>
//#include <stdio.h>
//
//#include "o_objet.h"
//#include "u_table.h"
//#include "t_geometrie.h"
//
//#define max_tab 20
//// inclusion du prototype de la fonction de calcul de points sur une courbe
//// de Nurbs
//
///* déclaration de la structure nanoedit */
//
//struct courbe_nurbs
//{
//  Table_quadruplet Pts_Controle ;
//  Table_quadruplet Courbe ;
//  double *vect_nod;
//  int degre;
//  int nb_points ;
//} ;
//
//int nb_morceaux(int k, int nb_pt_controle) /// Donne le nombre de morceaux du vecteur nodal. Ok!
//{
////    int result=0,
////        i;
////    for(i=0;(i+k-1)<nb_pt_controle;i++)
////    {
////        result++;
////    }
////    return result;
//    return (nb_pt_controle-k+1);
//}
//
//void remplir_vect_nod(double *vect_nod,int k,int nb_pt_controle) /// Remplis le vecteur nodal qui est en entrée. Ok!
//{
//    int i,
//        morceaux=nb_pt_controle-k+1;//nb_morceaux(k,nb_pt_controle);
//
//    for(i=0;i<k;i++)
//    {
//        vect_nod[i]=0;
//    }
//    for(i=k;i<k+morceaux;i++)
//    {
//        vect_nod[i]=(i-k+1.f)/morceaux;
//    }
//    for(i=morceaux+k;i<morceaux+2*k-1;i++)
//    {
//        vect_nod[i]=1;
//    }
//}
//
//Quadruplet calcul_point_courbe(struct courbe_nurbs *o,double pas) // pas de cas ou u =0 et u=1 traiter dans une autre fonction.
//{
//    int degre=o->degre,
//        indice=0,
//        indice_pt_control=0, //indique le point de control de depart.
//        j,i=degre,r,
//        k=o->degre+1;
//
//    Quadruplet resultat;
//    Table_quadruplet points_temp;
//    ALLOUER(points_temp.table,o->Pts_Controle.nb);
//
//    double a;
//
//    while(o->vect_nod[i]!=1) // on sait ou se situe "pas" dans le vecteur nodal.
//    {
//        if(o->vect_nod[i]<pas && o->vect_nod[i+1]>pas)
//        {
//            indice_pt_control = indice;
//        }
//        indice++;
//        i++;
//    }
//
//    r=k-1+indice_pt_control;
//
//    for(j=0;j < o->Pts_Controle.nb;j++)
//    {
//        points_temp.table[j] = o->Pts_Controle.table[j];
//        points_temp.table[j].x*=points_temp.table[j].h;
//        points_temp.table[j].y*=points_temp.table[j].h;
//        points_temp.table[j].z*=points_temp.table[j].h;
//    }
//
//    for(j=1;j<=degre;j++) //boucle pour le degre
//    {
//        indice++;
//        for(i=r;i>=(r-k+1+j);i--)
//        {
//            a = ((pas- o->vect_nod[i])/(o->vect_nod[i+k-j]-o->vect_nod[i]));
//
//            points_temp.table[i].x = a * points_temp.table[i].x + (1-a) * points_temp.table[i-1].x;
//
//            points_temp.table[i].y = a * points_temp.table[i].y + (1-a) * points_temp.table[i-1].y;
//
//            points_temp.table[i].z = a * points_temp.table[i].z + (1-a) * points_temp.table[i-1].z;
//
//            points_temp.table[i].h = a * points_temp.table[i].h + (1-a) * points_temp.table[i-1].h;
//
//        }
//    }
//    i++;
//    points_temp.table[i].x/=points_temp.table[i].h;
//    points_temp.table[i].y/=points_temp.table[i].h;
//    points_temp.table[i].z/=points_temp.table[i].h;
//
//    resultat = points_temp.table[i];
//    free(points_temp.table);
//
//    return resultat;
//}
//
//Table_quadruplet calcul_courbe_nurbs(struct courbe_nurbs *o)
//{
//    double i;
//    double pas =0.0;
//    int indice = 1;
//
//    pas = 1.0/o->nb_points;
//    o->Courbe.table[0]=o->Pts_Controle.table[0];
//
//    for(i = pas; i < 1 ;i = i+pas,indice++)
//        o->Courbe.table[indice] = calcul_point_courbe(o,i);
//
//    o->Courbe.table[indice] = o->Pts_Controle.table[o->Pts_Controle.nb-1];
//    return o->Courbe;
//}
//
//
//
//static void changement(struct courbe_nurbs *o)
//{
//
//    if ( ! (UN_CHAMP_CHANGE(o)||CREATION(o)) )
//        return;
//
//    if (CHAMP_CHANGE(o, nb_points) ||  CHAMP_CHANGE(o, Pts_Controle) || CHAMP_CHANGE(o, degre))
//    {
//        if (o->nb_points > 0 || o->Courbe.nb >= 2)
//            free(o->Courbe.table);
//
//        if(o->degre > o->Pts_Controle.nb-1)
//            o->degre=o->Pts_Controle.nb-1;
//        else if(o->degre<1)
//            o->degre=1;
//
//        if(o->nb_points<50)
//            o->nb_points=50;
//
//        ALLOUER(o->Courbe.table,o->nb_points+1);
//        o->Courbe.nb = o->nb_points;
//
//        ALLOUER(o->vect_nod,o->degre+o->Pts_Controle.nb+1);
//        remplir_vect_nod(o->vect_nod,o->degre+1,o->Pts_Controle.nb);
//
//
//        o->Courbe = calcul_courbe_nurbs(o);
//
//      /* appel de la fonction de calcul et stockage du résultat
//         dans la structure déclarée ci-dessus */
//        free(o->vect_nod);
//
//        printf("dans changement \n");
//    }
//}
//
//
//static void affiche_courbe_nurbs(struct courbe_nurbs *o)
//{
//  int j;
//
//    glBegin(GL_POINTS);
//    glColor3d(1,0,0);
//
//    for(j=0 ; j< o->Courbe.nb; j++){
//        glVertex3f(o->Courbe.table[j].x,o->Courbe.table[j].y,o->Courbe.table[j].z);
//        }
//
//    glEnd();
//
//    glBegin(GL_LINE) ;
//
//    glColor3d(0,1,0);
//    for(j=0; j < o->Pts_Controle.nb-1; j++){
//        glVertex3f(o->Pts_Controle.table[j].x,o->Pts_Controle.table[j].y,o->Pts_Controle.table[j].z);
//        glVertex3f(o->Pts_Controle.table[j+1].x,o->Pts_Controle.table[j+1].y,o->Pts_Controle.table[j+1].z);
//    }
//
//    glEnd();
//}
//
//
//
//CLASSE(courbe_nurbs, struct courbe_nurbs,
//
//    CHAMP(Pts_Controle, L_table_point P_table_quadruplet
//             Extrait Obligatoire Edite Affiche Sauve)
//
//    CHAMP(nb_points, LABEL("Nombre de points")
//             L_entier Extrait Affiche Edite Sauve DEFAUT("500"))
//
//    CHAMP(Courbe, L_table_point P_table_quadruplet
//            Affiche Sauve)
//
//    CHAMP(degre, LABEL("Degre de la courbe")
//            L_entier Extrait Affiche Edite Sauve DEFAUT("3"))
//
//    CHANGEMENT(changement)
//    CHAMP_VIRTUEL(L_affiche_gl(affiche_courbe_nurbs))
//
//
//    MENU("Courbe Nurbs")
//    EVENEMENT("CN")
//)
//
